# -*- coding: utf-8 -*-
"""
    xfree.forum.forms
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：它提供了论坛视图所需的表单。
    作者：xfree
    邮箱：cy_83k@qq.com
"""

import logging

from flask import current_app
from flask_babelplus import lazy_gettext as _
from flask_wtf import FlaskForm
from wtforms import (
    BooleanField,
    SelectMultipleField,
    StringField,
    SubmitField,
    TextAreaField,
)
from wtforms.validators import DataRequired, Length, Optional

from xfree.forum.models import Forum, Post, Report, Topic
from xfree.user.models import User
from xfree.utils.helpers import time_utcnow

# 获取日志记录器
logger = logging.getLogger(__name__)


class PostForm(FlaskForm):
    """
    用于发布帖子的表单类。
    """
    content = TextAreaField(
        _("Content"),
        validators=[
            DataRequired(message=_("You cannot post a reply without content."))
        ],
    )
    submit = SubmitField(_("Reply"))

    def save(self, user, topic):
        """
        保存帖子的方法。

        :param user: 发布帖子的用户
        :param topic: 帖子所属的主题
        :return: 保存后的帖子对象
        """
        post = Post(content=self.content.data)
        current_app.pluggy.hook.xfree_form_post_save(form=self, post=post)
        return post.save(user=user, topic=topic)


class QuickreplyForm(PostForm):
    """
    快速回复表单类，继承自PostForm。
    """
    pass


class ReplyForm(PostForm):
    """
    回复表单类，继承自PostForm。
    """
    track_topic = BooleanField(
        _("Track this topic"), default=False, validators=[Optional()]
    )

    def __init__(self, *args, **kwargs):
        """
        初始化方法。

        :param args: 位置参数
        :param kwargs: 关键字参数
        """
        self.post = kwargs.get("obj", None)
        PostForm.__init__(self, *args, **kwargs)

    def save(self, user, topic):
        """
        保存回复的方法。

        :param user: 回复的用户
        :param topic: 回复所属的主题
        :return: 保存后的回复对象
        """
        # 如果是新回复
        if self.post is None:
            self.post = Post(content=self.content.data)
        else:
            self.post.date_modified = time_utcnow()
            self.post.modified_by = user.username

        if self.track_topic.data:
            user.track_topic(topic)
        else:
            user.untrack_topic(topic)

        current_app.pluggy.hook.xfree_form_post_save(form=self, post=self.post)
        return self.post.save(user=user, topic=topic)


class TopicForm(FlaskForm):
    """
    主题表单类。
    """
    title = StringField(
        _("Topic title"),
        validators=[DataRequired(message=_("Please choose a title for your topic."))],
    )
    content = TextAreaField(
        _("Content"),
        validators=[
            DataRequired(message=_("You cannot post a reply without content."))
        ],
    )
    track_topic = BooleanField(
        _("Track this topic"), default=False, validators=[Optional()]
    )
    submit = SubmitField(_("Post topic"))

    def save(self, user, forum):
        """
        保存主题的方法。

        :param user: 发布主题的用户
        :param forum: 主题所属的论坛
        :return: 保存后的主题对象
        """
        topic = Topic(title=self.title.data, content=self.content.data)

        if self.track_topic.data:
            user.track_topic(topic)
        else:
            user.untrack_topic(topic)

        current_app.pluggy.hook.xfree_form_topic_save(form=self, topic=topic)
        return topic.save(user=user, forum=forum)


class NewTopicForm(TopicForm):
    """
    新建主题表单类，继承自TopicForm。
    """
    pass


class EditTopicForm(TopicForm):
    """
    编辑主题表单类，继承自TopicForm。
    """
    submit = SubmitField(_("Save topic"))

    def __init__(self, *args, **kwargs):
        """
        初始化方法。

        :param args: 位置参数
        :param kwargs: 关键字参数
        """
        self.topic = kwargs.get("obj").topic
        TopicForm.__init__(self, *args, **kwargs)

    def populate_obj(self, *objs):
        """
        用表单字段的数据填充传入对象的属性。

        :param objs: 要填充的对象
        """
        for obj in objs:
            super(EditTopicForm, self).populate_obj(obj)

    def save(self, user, forum):
        """
        保存编辑后的主题的方法。

        :param user: 编辑主题的用户
        :param forum: 主题所属的论坛
        :return: 保存后的主题对象
        """
        if self.track_topic.data:
            user.track_topic(self.topic)
        else:
            user.untrack_topic(self.topic)

        if (
            self.topic.last_post_id == forum.last_post_id
            and self.title.data!= forum.last_post_title
        ):
            forum.last_post_title = self.title.data

        self.topic.first_post.date_modified = time_utcnow()
        self.topic.first_post.modified_by = user.username

        current_app.pluggy.hook.xfree_form_topic_save(form=self, topic=self.topic)
        return self.topic.save(user=user, forum=forum)


class ReportForm(FlaskForm):
    """
    举报表单类。
    """
    reason = TextAreaField(
        _("Reason"),
        validators=[
            DataRequired(message=_("What is the reason for reporting this post?"))
        ],
    )
    submit = SubmitField(_("Report post"))

    def save(self, user, post):
        """
        保存举报信息的方法。

        :param user: 举报的用户
        :param post: 被举报的帖子
        :return: 保存后的举报对象
        """
        report = Report(reason=self.reason.data)
        return report.save(post=post, user=user)


class UserSearchForm(FlaskForm):
    """
    用户搜索表单类。
    """
    search_query = StringField(
        _("Search"), validators=[DataRequired(), Length(min=3, max=50)]
    )
    submit = SubmitField(_("Search"))

    def get_results(self):
        """
        获取搜索结果的方法。

        :return: 用户搜索结果
        """
        query = self.search_query.data
        return User.query.whooshee_search(query)


class SearchPageForm(FlaskForm):
    """
    搜索页面表单类。
    """
    search_query = StringField(
        _("Criteria"), validators=[DataRequired(), Length(min=3, max=50)]
    )
    search_types = SelectMultipleField(
        _("Content"),
        validators=[DataRequired()],
        choices=[
            ("post", _("Post")),
            ("topic", _("Topic")),
            ("forum", _("Forum")),
            ("user", _("Users")),
        ],
    )
    submit = SubmitField(_("Search"))

    def get_results(self):
        """
        获取搜索结果的方法。

        :return: 根据选择的搜索类型得到的搜索结果
        """
        # 由于表单加载时数据库尚未初始化，查询对象不能在类中实例化
        search_actions = {
            "post": Post.query.whooshee_search,
            "topic": Topic.query.whooshee_search,
            "forum": Forum.query.whooshee_search,
            "user": User.query.whooshee_search,
        }

        query = self.search_query.data
        types = self.search_types.data
        results = {}

        for search_type in search_actions.keys():
            if search_type in types:
                results[search_type] = search_actions[search_type](query)

        return results